using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Reflection;
using ObjectLib;

namespace ObjectParser
{
	/// <summary>
	/// Summary description for FormCategorize.
	/// </summary>
	public class FormCategorize : System.Windows.Forms.Form
	{
		private System.Windows.Forms.ComboBox comboField;
		private System.Windows.Forms.Label labelItemName;
		private System.Windows.Forms.Button butSkipBack;
		private System.Windows.Forms.Button butSkipAhead;
		private System.Windows.Forms.Button butLast;
		private System.Windows.Forms.Button butNext;
		private System.Windows.Forms.Label labelStatus;
		private System.Windows.Forms.CheckBox checkAutoSkip;
		private System.Windows.Forms.CheckBox checkFlash;
		private System.Windows.Forms.Timer timerFlash;
		private System.ComponentModel.IContainer components;
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.comboField = new System.Windows.Forms.ComboBox();
			this.labelItemName = new System.Windows.Forms.Label();
			this.butSkipBack = new System.Windows.Forms.Button();
			this.butSkipAhead = new System.Windows.Forms.Button();
			this.butLast = new System.Windows.Forms.Button();
			this.butNext = new System.Windows.Forms.Button();
			this.labelStatus = new System.Windows.Forms.Label();
			this.checkAutoSkip = new System.Windows.Forms.CheckBox();
			this.timerFlash = new System.Windows.Forms.Timer(this.components);
			this.checkFlash = new System.Windows.Forms.CheckBox();
			this.SuspendLayout();
			// 
			// comboField
			// 
			this.comboField.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.comboField.DisplayMember = "Name";
			this.comboField.Location = new System.Drawing.Point(8, 8);
			this.comboField.Name = "comboField";
			this.comboField.Size = new System.Drawing.Size(328, 21);
			this.comboField.TabIndex = 0;
			this.comboField.KeyDown += new System.Windows.Forms.KeyEventHandler(this.comboField_KeyDown);
			this.comboField.KeyUp += new System.Windows.Forms.KeyEventHandler(this.comboField_KeyUp);
			this.comboField.SelectedIndexChanged += new System.EventHandler(this.comboField_SelectedIndexChanged);
			// 
			// labelItemName
			// 
			this.labelItemName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.labelItemName.Location = new System.Drawing.Point(8, 32);
			this.labelItemName.Name = "labelItemName";
			this.labelItemName.Size = new System.Drawing.Size(328, 23);
			this.labelItemName.TabIndex = 1;
			// 
			// butSkipBack
			// 
			this.butSkipBack.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
			this.butSkipBack.Location = new System.Drawing.Point(8, 232);
			this.butSkipBack.Name = "butSkipBack";
			this.butSkipBack.Size = new System.Drawing.Size(88, 23);
			this.butSkipBack.TabIndex = 2;
			this.butSkipBack.Text = "<< Skip Back";
			this.butSkipBack.Click += new System.EventHandler(this.butSkipBack_Click);
			// 
			// butSkipAhead
			// 
			this.butSkipAhead.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
			this.butSkipAhead.Location = new System.Drawing.Point(248, 232);
			this.butSkipAhead.Name = "butSkipAhead";
			this.butSkipAhead.Size = new System.Drawing.Size(88, 23);
			this.butSkipAhead.TabIndex = 3;
			this.butSkipAhead.Text = "Skip Ahead >>";
			this.butSkipAhead.Click += new System.EventHandler(this.butSkipAhead_Click);
			// 
			// butLast
			// 
			this.butLast.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
			this.butLast.Location = new System.Drawing.Point(96, 232);
			this.butLast.Name = "butLast";
			this.butLast.Size = new System.Drawing.Size(80, 23);
			this.butLast.TabIndex = 4;
			this.butLast.Text = "< Last";
			this.butLast.Click += new System.EventHandler(this.butLast_Click);
			// 
			// butNext
			// 
			this.butNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
			this.butNext.Location = new System.Drawing.Point(176, 232);
			this.butNext.Name = "butNext";
			this.butNext.Size = new System.Drawing.Size(72, 23);
			this.butNext.TabIndex = 5;
			this.butNext.Text = "Next >";
			this.butNext.Click += new System.EventHandler(this.butNext_Click);
			// 
			// labelStatus
			// 
			this.labelStatus.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.labelStatus.Location = new System.Drawing.Point(8, 168);
			this.labelStatus.Name = "labelStatus";
			this.labelStatus.Size = new System.Drawing.Size(328, 23);
			this.labelStatus.TabIndex = 6;
			// 
			// checkAutoSkip
			// 
			this.checkAutoSkip.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.checkAutoSkip.Checked = true;
			this.checkAutoSkip.CheckState = System.Windows.Forms.CheckState.Checked;
			this.checkAutoSkip.Location = new System.Drawing.Point(8, 208);
			this.checkAutoSkip.Name = "checkAutoSkip";
			this.checkAutoSkip.Size = new System.Drawing.Size(328, 24);
			this.checkAutoSkip.TabIndex = 7;
			this.checkAutoSkip.Text = ">> Skip Ahead after selection.";
			// 
			// timerFlash
			// 
			this.timerFlash.Interval = 1000;
			this.timerFlash.Tick += new System.EventHandler(this.timerFlash_Tick);
			// 
			// checkFlash
			// 
			this.checkFlash.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.checkFlash.Checked = true;
			this.checkFlash.CheckState = System.Windows.Forms.CheckState.Checked;
			this.checkFlash.Location = new System.Drawing.Point(8, 184);
			this.checkFlash.Name = "checkFlash";
			this.checkFlash.Size = new System.Drawing.Size(328, 24);
			this.checkFlash.TabIndex = 8;
			this.checkFlash.Text = "Flash highlights.";
			// 
			// FormCategorize
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(344, 262);
			this.Controls.Add(this.checkFlash);
			this.Controls.Add(this.checkAutoSkip);
			this.Controls.Add(this.labelStatus);
			this.Controls.Add(this.butNext);
			this.Controls.Add(this.butLast);
			this.Controls.Add(this.butSkipAhead);
			this.Controls.Add(this.butSkipBack);
			this.Controls.Add(this.labelItemName);
			this.Controls.Add(this.comboField);
			this.MinimumSize = new System.Drawing.Size(352, 0);
			this.Name = "FormCategorize";
			this.Text = "Categorize";
			this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.FormCategorize_KeyDown);
			this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.FormCategorize_KeyUp);
			this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.FormCategorize_MouseMove);
			this.MouseEnter += new System.EventHandler(this.FormCategorize_MouseEnter);
			this.ResumeLayout(false);

		}
		#endregion

		public Type CatType;
		/// <summary>
		/// The contents of the combo box.
		/// </summary>
		public FieldInfo[] CatFields;
		/// <summary>
		///	Gives the number of possible categorization responses for a field.
		/// </summary>
		public int[] FieldSize;
		public int ActiveField;
		public FormParse FormParse;
		public RadioButton[] RadioButtons;
		public object Current;
		/// <summary>
		/// Clears any radio buttons that may exist.
		/// </summary>
		public void ClearRadio()
		{
			//	Clear any old radio buttons.
			if(RadioButtons != null )
				for(int i=0; i<RadioButtons.Length; i++)
					this.Controls.Remove(RadioButtons[i]);
		}

		/// <summary>
		/// Initializes the radio buttons assuming the current trial is a multiple choice trial.
		/// Assume that layout logic is suspended.
		/// </summary>
		public void InitCat(object obj)
		{
			this.SuspendLayout();

			//	Clear the radio buttons.
			ClearRadio();

			//	Set the current parsed object or contour.
			Current = obj;

			if(obj != null)
			{
				//	Get the categorization data
				object catData = null;
				ParsedObject po = null;
				if( obj.GetType()==typeof(ParsedObject) )
				{
					po = ((ParsedObject)obj);
					catData = po.CatData;
				}
				else if( obj.GetType()==typeof(ContourF) )
				{
					po = ((ContourF)obj).PolyOwner.Owner;
					catData = ((ContourF)obj).CatData;
				}

				//	The height of each radio button.
				int height = 24;
				//	The number of choices and the names of the enumerator (if applicable)
				string[] names = new string[0];
				System.Array vals = new object[0];
				int nChoices= FieldSize[ActiveField]+1;
				if(CatFields[ActiveField].FieldType.IsEnum)
				{
					nChoices=FieldSize[ActiveField];
					names = Enum.GetNames( CatFields[ActiveField].FieldType );
					vals = Enum.GetValues( CatFields[ActiveField].FieldType );
				}
				object result = CatFields[ActiveField].GetValue(catData);
				//	Initialize the radio buttons.
				RadioButtons = new RadioButton[nChoices];
				//	Compute the total height of the control and set the control height.
				int totalHeight = nChoices*height+60
					+labelItemName.Height+comboField.Height+labelStatus.Height+butSkipBack.Height
					+checkAutoSkip.Height+checkFlash.Height;
				this.Height = totalHeight;

				this.ResumeLayout();
				this.SuspendLayout();

				EventHandler eh = new EventHandler(Radio_Click);

				for(int c=0; c<nChoices; c++)
				{
					RadioButtons[c] = new RadioButton();
					RadioButtons[c].Location = new Point(8, labelItemName.Bottom+8+height*c);
					RadioButtons[c].Size = new Size(this.Width-16, height);
					if(CatFields[ActiveField].FieldType.IsEnum)
					{
						RadioButtons[c].Text = Convert.ToString(c) + "  " + names[c];
						RadioButtons[c].Tag = vals.GetValue(c);
					}
					else
					{
						if(c==0)
							RadioButtons[c].Text = "0  Uncategorized";
						else
							RadioButtons[c].Text = Convert.ToString(c);
						RadioButtons[c].Tag = c;
					}

					if(RadioButtons[c].Tag.GetHashCode() == result.GetHashCode())
						RadioButtons[c].Checked = true;

					RadioButtons[c].Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
					RadioButtons[c].Click += eh;
					this.Controls.Add(RadioButtons[c]);
				}
				//	Initialize labelItemName
				labelItemName.Text = po.MediumName;
				ViewAndActivate( obj );
				
				//	Update status
				if (obj.GetType()==typeof(ParsedObject))
					labelStatus.Text = "Categorizing " + po.MediumName + ".";
				else
					labelStatus.Text = "Categorizing a contour in " + po.MediumName + ".";

				this.ResumeLayout();

				timerFlash.Start();
			}
		}
		public void ViewAndActivate(object obj)
		{
			FormParse.ViewAndActivate( obj, 2, true, false );
		}
		public void ExecuteCat(object catValue)
		{
			if(Current != null)
			{
				object catData = null;
				if( Current.GetType()==typeof(ParsedObject) )
					catData = ((ParsedObject)Current).CatData;
				else if( Current.GetType()==typeof(ContourF) )
					catData = ((ContourF)Current).CatData;
				//	Categorize an object.  No switching behavior is implicated.
				//	(113, ObjectCategorizationData dat, FieldInfo categorizationField, object newValue, object oldValue)
				ArrayList macro = new ArrayList();
				macro.Add( 113 );
				macro.Add( catData );
				macro.Add( CatFields[ActiveField] );
				macro.Add( catValue );
				macro.Add( CatFields[ActiveField].GetValue(catData) );
				FormParse.UndoStack.Add(macro);
				FormParse.RedoStack.Clear();
				FormParse.ExecuteAction(true, macro, false);
			}
		}
		public FormCategorize(FormParse FormParse, Type CatType, string activeFieldName)
		{
			InitializeComponent();

			MouseEventHandler meh = new MouseEventHandler(FormCategorize_MouseMove);
			int i;
			for(i=0; i<this.Controls.Count; i++)
				this.Controls[i].MouseMove += meh;

			
			this.FormParse = FormParse;
			this.Owner = FormParse;

			this.CatType = CatType;
			ActiveField = 0;

			if(CatType==typeof(ContourCategorizationData) || CatType==typeof(ObjectCategorizationData))
			{
				if( CatType==typeof(ObjectCategorizationData) )
				{
					FieldSize = ObjectCategorizationData.FieldSizes;
					CatFields = ObjectCategorizationData.Fields;
				}
				else if( CatType==typeof(ContourCategorizationData) )
				{
					FieldSize = ContourCategorizationData.FieldSizes;
					CatFields = ContourCategorizationData.Fields;
				}

				/*
				//	Initialize CatFields and ActiveField.
				FieldInfo[] allFields = CatType.GetFields();
				for(i=0; i<allFields.Length; i++)
				{
					typ = allFields[i].FieldType;
					if( !allFields[i].IsStatic && (typ==typeof(int) || typ.IsEnum)  )
						len++;
				}
				CatFields = new FieldInfo[len];
				for(i=allFields.Length-1; i>=0; i--)
				{
					typ = allFields[i].FieldType;
					if( !allFields[i].IsStatic && (typ==typeof(int) || typ.IsEnum)  )
					{
						CatFields[--len] = allFields[i];
						if( CatFields[len].Name==activeFieldName )
							ActiveField = len;
					}
				}
				*/

				for(i=0; i<CatFields.Length; i++)
					this.comboField.Items.Add(CatFields[i]);
				
				if( CatType==typeof(ObjectCategorizationData) )
				{
					ParsedObjectList pol = new ParsedObjectList();
					FormParse.Opd.RootCategory.ObjectsCategorizedAs( pol, CatFields[ActiveField], 0 );
					if(pol.Count==0)
					{
						FormParse.Opd.InventoryParsedObjects(pol);
						this.labelStatus.Text = "No uncategorized objects in " + CatFields[ActiveField].Name + ".";
					}
					if(pol.Count>0)
						Current = pol[0];
				}
				else if( CatType==typeof(ContourCategorizationData) )
				{
					ContourFarray cfa = new ContourFarray(true);
					FormParse.Opd.RootCategory.ContoursCategorizedAs( cfa, CatFields[ActiveField], 0 );
					if(cfa.Count==0)
					{
						FormParse.Opd.RootCategory.InventoryContours( cfa );
						this.labelStatus.Text = "No uncategorized contours in " + CatFields[ActiveField].Name + ".";
					}
					if(cfa.Count>0)
					{
						Current = cfa[0];
					}
				}
				this.comboField.SelectedItem = CatFields[ActiveField];
			}
			else
				throw new ApplicationException("Unhandled type CatType.");
		}
		private void FormCategorize_MouseEnter(object sender, System.EventArgs e)
		{
			if(!this.Focused)
				this.Focus();
			if(FormParse.Opd.ActiveObject != Current)
			{
				if( CatType==typeof(ObjectCategorizationData) )
					InitCat(FormParse.Opd.ActiveObject);
				else if( CatType==typeof(ObjectCategorizationData) )
					InitCat(FormParse.Opd.ActiveContour);
			}
		}
		private void FormCategorize_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if( !this.ContainsFocus )
				this.Focus();
		}
		private void FormCategorize_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			if(e.KeyCode==Keys.Z && e.Control)
			{
				FormParse.Undo();
				InitCat(FormParse.Opd.ActiveObject);
			}
			else if(e.KeyCode==Keys.Y && e.Control)
			{
				FormParse.Redo();
				InitCat(FormParse.Opd.ActiveObject);
			}
		}
		public void FormCategorize_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			if(RadioButtons != null)
			{
				if(e.KeyCode == Keys.D0 || e.KeyCode==Keys.NumPad0)
				{
					if(RadioButtons.Length>=1)
						RadioButtons[0].PerformClick();
				}
				else if(e.KeyCode == Keys.D1 || e.KeyCode==Keys.NumPad1)
				{
					if(RadioButtons.Length>=2)
						RadioButtons[1].PerformClick();
				}
				else if(e.KeyCode == Keys.D2 || e.KeyCode==Keys.NumPad2)
				{
					if(RadioButtons.Length>=3)
						RadioButtons[2].PerformClick();
				}
				else if(e.KeyCode == Keys.D3 || e.KeyCode==Keys.NumPad3)
				{
					if(RadioButtons.Length>=4)
						RadioButtons[3].PerformClick();
				}
				else if(e.KeyCode == Keys.D4 || e.KeyCode==Keys.NumPad4)
				{
					if(RadioButtons.Length>=5)
						RadioButtons[4].PerformClick();
				}
				else if(e.KeyCode == Keys.D5 || e.KeyCode==Keys.NumPad5)
				{
					if(RadioButtons.Length>=6)
						RadioButtons[5].PerformClick();
				}
				else if(e.KeyCode == Keys.D6 || e.KeyCode==Keys.NumPad6)
				{
					if(RadioButtons.Length>=7)
						RadioButtons[6].PerformClick();
				}
				else if(e.KeyCode == Keys.D7 || e.KeyCode==Keys.NumPad7)
				{
					if(RadioButtons.Length>=8)
						RadioButtons[7].PerformClick();
				}
				else if(e.KeyCode == Keys.D8 || e.KeyCode==Keys.NumPad8)
				{
					if(RadioButtons.Length>=9)
						RadioButtons[8].PerformClick();
				}
				else if(e.KeyCode == Keys.D9 || e.KeyCode==Keys.NumPad9)
				{
					if(RadioButtons.Length>=1)
						RadioButtons[9].PerformClick();
				}
			}
		}
		private void Radio_Click(object sender, System.EventArgs e)
		{
			RadioButton snd = (RadioButton)sender;
			snd.Checked = true;
			ExecuteCat( snd.Tag );
			if(this.checkAutoSkip.Checked)
				butSkipAhead.PerformClick();
		}
		private void butSkipBack_Click(object sender, System.EventArgs e)
		{
			Move(-1, true);
		}
		private void butLast_Click(object sender, System.EventArgs e)
		{
			Move(-1, false);
		}
		private void butNext_Click(object sender, System.EventArgs e)
		{
			Move(+1, false);
		}
		private void butSkipAhead_Click(object sender, System.EventArgs e)
		{
			Move(+1, true);
		}
		/// <summary>
		/// Moves or skips ahead in the order of things to be categorized.
		/// </summary>
		/// <param name="direction">-1 moves back, +1 moves ahead</param>
		/// <param name="skip">If true, objects that have already been categorized are skipped.</param>
		public new void Move(int direction, bool skip)
		{
			//	Temporarily change the current value.
			int currentVal=0;

			object catData = null;

			if(this.CatType == typeof(ObjectCategorizationData))
			{
				if(Current != null)
				{
					catData = ((ParsedObject)Current).CatData;
					currentVal = (int)CatFields[ActiveField].GetValue(catData);
					CatFields[ActiveField].SetValue(catData, 0);
				}

				ParsedObjectList pol = new ParsedObjectList();
				if(skip)
					FormParse.Opd.RootCategory.ObjectsCategorizedAs( pol, CatFields[ActiveField], 0 );
				else
					FormParse.Opd.RootCategory.InventoryParsedObjects( pol );

				//	Change the current value back to the original value.
				if(Current != null)
					CatFields[ActiveField].SetValue(catData, currentVal);

				int ind = pol.IndexOf( (ParsedObject)Current );
				if(ind<0)
					ind=0;
				else
				{
					pol.RemoveAt(ind);
					if(direction==-1)
						ind--;
					if(ind >= pol.Count)
						ind = 0;
					if(ind<0)
						ind=pol.Count-1;
				}
				if(pol.Count > 0)
				{
					Current = pol[ind];
					ViewAndActivate(  Current );	//	This function handles the Undo / Redo stuff.
					InitCat(Current);
				}
				labelStatus.Text = Convert.ToString(pol.Count) + " uncategorized along the " + CatFields[ActiveField].Name + " dimension.";
			}
			else if(this.CatType == typeof(ContourCategorizationData))
			{
				if(Current != null)
				{
					catData = ((ContourF)Current).CatData;
					currentVal = (int)CatFields[ActiveField].GetValue(catData);
					CatFields[ActiveField].SetValue(catData, 0);
				}

				ContourFarray cfa = new ContourFarray(true);
				if(skip)
					FormParse.Opd.RootCategory.ContoursCategorizedAs( cfa, CatFields[ActiveField], 0 );
				else
					FormParse.Opd.RootCategory.InventoryContours( cfa );

				//	Change the current value back to the original value.
				if(Current != null)
					CatFields[ActiveField].SetValue(catData, currentVal);

				int ind = cfa.IndexOf( Current );
				if(ind<0)
					ind=0;
				else
				{
					cfa.RemoveAt(ind);
					if(direction==-1)
						ind--;
					if(ind >= cfa.Count)
						ind = 0;
					if(ind<0)
						ind=cfa.Count-1;
				}
				if(cfa.Count > 0)
				{
					Current = cfa[ind];
					ViewAndActivate( Current );	//	This function handles the Undo / Redo stuff.
					InitCat(Current);
				}
				labelStatus.Text = Convert.ToString(cfa.Count) + " uncategorized along the " + CatFields[ActiveField].Name + " dimension.";
			}
		}
		private void comboField_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			ActiveField = comboField.SelectedIndex;
			if(ActiveField<0 || ActiveField>=CatFields.Length)
				ActiveField=0;
			InitCat(Current);
		}

		private void timerFlash_Tick(object sender, System.EventArgs e)
		{
			if(FormParse != null && this.checkFlash.Checked)
			{
				FormParse.bViewAll.ImageIndex = 1-FormParse.bViewAll.ImageIndex;
				FormParse.bViewAll.Invalidate();
				FormParse.Pb.Invalidate();
			}
		}

		private void comboField_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			comboField.SelectedIndex = this.ActiveField;
			this.FormCategorize_KeyUp(sender, e);
		}

		private void comboField_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			comboField.SelectedIndex = this.ActiveField;
			this.FormCategorize_KeyDown(sender, e);
		}

	}
}